﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.ComponentModel;

namespace WickedFlame.Core.History
{
    public delegate void HistoryEventHandler(object sender, HistoryEventArgs e);

    //public delegate void HistoryListEventHandler(object sender, HistoryListEventArgs e);

    public class HistoryManager : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(string name)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }

        //public event HistoryEventHandler CommandAdded;

        //public event HistoryEventHandler CommandUndo;

        //public event HistoryEventHandler CommandRedo;

        //public event HistoryListEventHandler ListTrimmed;

        //List<ShapeList> shapeLists;
        DrawingCanvas canvas;

        //List<HistoryCommand> historyList;
        ObservableCollection<HistoryCommand> historyList;
        int nextUndo;

        public HistoryManager(DrawingCanvas canvas)
        {
            //shapeLists = new List<ShapeList>();
            this.canvas = canvas;
            ClearHistory();
        }

        /// <summary>
        /// Return true if Undo operation is available
        /// </summary>
        public bool CanUndo
        {
            get
            {
                if (nextUndo < 0 ||
                    nextUndo > historyList.Count - 1) 
                {
                    return false;
                }

                return true;
            }
        }

        /// <summary>
        /// Return true if Redo operation is available
        /// </summary>
        public bool CanRedo
        {
            get
            {
                if (nextUndo == historyList.Count - 1)
                {
                    return false;
                }

                return true;
            }
        }

        /// <summary>
        /// Clear History
        /// </summary>
        public void ClearHistory()
        {
            historyList = new ObservableCollection<HistoryCommand>();
            nextUndo = -1;
            NotifyPropertyChanged("SelectedHistoryIndex");
        }

        /// <summary>
        /// Add new command to history.
        /// Called by client after executing some action.
        /// </summary>
        /// <param name="command"></param>
        public void PushHistoryCommand(HistoryCommand command)
        {
            // Purge history list
            this.TrimHistoryList();

            historyList.Add(command);
            nextUndo++;
            NotifyPropertyChanged("SelectedHistoryIndex");
        }

        /// <summary>
        /// Execute the Command object's undo method
        /// </summary>
        public void Undo()
        {
            if (!CanUndo)
                return;

            // Get the Command object to be undone
            HistoryCommand command = historyList[nextUndo];

            if (command is LayerAddedCommand ||
                command is LayerDeleteCommand)
            {
                command.Undo(null);
            }
            else
            {
                command.Undo(canvas.Layers[command.LayerIndex].ShapeList);
            }
            nextUndo--;
            NotifyPropertyChanged("SelectedHistoryIndex");
        }

        /// <summary>
        /// Redo
        /// </summary>
        public void Redo()
        {
            if (!CanRedo)
                return;

            // Get the Command object to redo
            int itemToRedo = nextUndo + 1;
            HistoryCommand command = historyList[itemToRedo];

            if (command is LayerAddedCommand ||
                command is LayerDeleteCommand)
            {
                command.Redo(null);
            }
            else
            {
                command.Redo(canvas.Layers[command.LayerIndex].ShapeList);
            }
            nextUndo++;
            NotifyPropertyChanged("SelectedHistoryIndex");
        }

        private void TrimHistoryList()
        {
            // Exit if no items in History list
            if (historyList.Count == 0)
            {
                return;
            }

            // Exit if NextUndo points to last item on the list
            if (nextUndo == historyList.Count - 1)
            {
                return;
            }

            // Purge all items below the NextUndo pointer
            try
            {
                for (int i = historyList.Count - 1; i > nextUndo; i--)
                {
                    historyList.RemoveAt(i);
                }
            }
            catch (ArgumentOutOfRangeException) { }

            NotifyPropertyChanged("SelectedHistoryIndex");
        }

        public void RemoveLastCommand()
        {
            if (nextUndo <= 0)
                return;

            historyList.RemoveAt(historyList.Count - 1);
            nextUndo--;
        }

        public int SelectedHistoryIndex
        {
            get
            {
                return nextUndo;
            }
            set
            {
                nextUndo = value;
            }
        }

        public ObservableCollection<HistoryCommand> HistoryList
        {
            get
            {
                return historyList;
            }
        }
    }

    public class HistoryEventArgs : EventArgs
    {
        HistoryCommand command;
        int index;

        public HistoryEventArgs(HistoryCommand command, int index)
        {
            this.command = command;
            this.index = index;
        }

        public HistoryCommand Command
        {
            get
            {
                return command;
            }
        }

        public int Index
        {
            get
            {
                return index;
            }
        }
    }

    //public class HistoryListEventArgs : EventArgs
    //{
    //    //List<HistoryCommand> command;
    //    ObservableCollection<HistoryCommand> command;
    //    int index;

    //    //public HistoryListEventArgs(List<HistoryCommand> command, int index)
    //    public HistoryListEventArgs(ObservableCollection<HistoryCommand> command, int index)
    //    {
    //        this.command = command;
    //        this.index = index;
    //    }

    //    //public List<HistoryCommand> Command
    //    public ObservableCollection<HistoryCommand> Command
    //    {
    //        get
    //        {
    //            return command;
    //        }
    //    }

    //    public int Index
    //    {
    //        get
    //        {
    //            return index;
    //        }
    //    }
    //}
}
